/* OTA example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"

#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_ota_ops.h"

#include "nvs.h"
#include "nvs_flash.h"


//-------------------------------------------------------
//#include "soc/gpio_struct.h"//xgy add




#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#define EXAMPLE_SERVER_IP   CONFIG_SERVER_IP//局域网

//#define EXAMPLE_SERVER_IP   "127.0.0.1"//"http://localhost:8070/"//CONFIG_SERVER_IP//本地 遗憾
										//不行的原因是ESP32 在.31 网段 而你现在主机在点 .1网段 当然家里的wifi就可以
#define EXAMPLE_SERVER_PORT CONFIG_SERVER_PORT
#define EXAMPLE_FILENAME CONFIG_EXAMPLE_FILENAME
#define BUFFSIZE 1024
#define TEXT_BUFFSIZE 1024

static const char *TAG = "ota";
/*an ota data write buffer ready to write to the flash*/
static char ota_write_data[BUFFSIZE + 1] = { 0 };
/*an packet receive buffer*/
static char text[BUFFSIZE + 1] = { 0 };
/* an image total length*/
static int binary_file_length = 0;
/*socket id*/
static int socket_id = -1;
static char http_request[64] = {0};

/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;

/* The event group allows multiple bits for each event,
   but we only care about one event - are we connected
   to the AP with an IP? */
const int CONNECTED_BIT = BIT0;


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#define	XGY_DEBUG

#define M_ENB_GPIO
#define	OTA_VERSION_MCU	((int)17)
#define	C_NOW_TIME	"2017930 11:37"

static const char *TAG_XGY = "ota_xgy";


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


#ifdef M_ENB_GPIO
/**
 * Brief:
 * This test code shows how to configure gpio and how to use gpio interrupt.
 *
 * GPIO status:
 * GPIO18: output
 * GPIO19: output
 * GPIO4:  input, pulled up, interrupt from rising edge and falling edge
 * GPIO5:  input, pulled up, interrupt from rising edge.
 *
 * Test:
 * Connect GPIO18 with GPIO4
 * Connect GPIO19 with GPIO5
 * Generate pulses on GPIO18/19, that triggers interrupt on GPIO4/5
 *
 */

#define GPIO_OUTPUT_IO_0    18
#define GPIO_OUTPUT_IO_1    19
#define GPIO_OUTPUT_PIN_SEL  ((1<<GPIO_OUTPUT_IO_0) | (1<<GPIO_OUTPUT_IO_1))
#define GPIO_INPUT_IO_0     4
#define GPIO_INPUT_IO_1     5
#define GPIO_INPUT_PIN_SEL  ((1<<GPIO_INPUT_IO_0) | (1<<GPIO_INPUT_IO_1))
#define ESP_INTR_FLAG_DEFAULT 0

static xQueueHandle gpio_evt_queue = NULL;

static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}

static void gpio_task_example(void* arg)
{
    uint32_t io_num;
    for(;;) {
        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
            printf("GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
        }
    }
}

#if 1//void delay_1us(void)
static void delay_1us(void)
{
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//10
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//20
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//30
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//40
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//50

	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//60
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//70
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//80
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//90
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//100
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//110
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//120
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//130
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");
	__asm__ volatile ("nop");//140
	


}
#endif

//#define	M_PWMIO_SET	GPIO.out_w1ts = (1<<GPIO_OUTPUT_IO_0);
//#define	M_PWMIO_CLR	GPIO.out_w1tc = (1<<GPIO_OUTPUT_IO_0);

#define	M_PWMIO_SET	GPIO.out_w1ts = (1<<GPIO_OUTPUT_IO_0)|(1<<GPIO_OUTPUT_IO_1);
#define	M_PWMIO_CLR	GPIO.out_w1tc = (1<<GPIO_OUTPUT_IO_0)|(1<<GPIO_OUTPUT_IO_1);



#define	C_RGB_R	0x00ff0000
#define	C_RGB_G	0x0000ff00
#define	C_RGB_B	0x000000ff
#define	C_RGB_RG	0x00ffff00
#define	C_RGB_GB	0x0000ffff
#define	C_RGB_BR	0x00ff00ff
#define	C_RGB_RGB	0x00ffffff
#define	C_RGB_G3	0x00003300
#define	C_RGB_OFF	0x00000000



#define	C_LEN_BUF_RGB	100
u32_t buf_RGB[C_LEN_BUF_RGB];


static void delay_2us(void)
{
	delay_1us();
	delay_1us();
}

static void delay_4us(void)
{
	delay_1us();
	delay_1us();
	delay_1us();
	delay_1us();
}



static void	send_head(u8_t data){
int count = 4;
		data <<= 4;
		while(count--)
		{
			//GPIO.out_w1tc = (1<<GPIO_OUTPUT_IO_0);//clr
			M_PWMIO_CLR
			if(data &(1<<7))
				delay_2us();
			else
				delay_1us();
			
			//GPIO.out_w1ts = (1<<GPIO_OUTPUT_IO_0);//set
			M_PWMIO_SET
			delay_4us();
			data <<= 1; 
		}
}
static void	send_preamble(void){
int count = 8;
u8_t data = 0x55;

		while(count--)
		{
			//GPIO.out_w1tc = (1<<GPIO_OUTPUT_IO_0);//clr
			M_PWMIO_CLR
			if(data &(1<<7))
				delay_2us();
			else
				delay_1us();
			
			//GPIO.out_w1ts = (1<<GPIO_OUTPUT_IO_0);//set
			M_PWMIO_SET
			delay_4us();
			data <<= 1; 
		}
}

static void	send_head_RGB(void){
	send_head(0x0A);
}


static	void	send_RGB(u32_t RGB_data){
int count = 24+1;

	RGB_data <<= 8;

	while(count--)
	{
		//GPIO.out_w1tc = (1<<GPIO_OUTPUT_IO_0);//clr
		//GPIO.out_w1tc = (1<<GPIO_OUTPUT_IO_1);//clr
		M_PWMIO_CLR
		if(RGB_data &(1<<31))
			delay_2us();
		else
			delay_1us();
		
		//GPIO.out_w1ts = (1<<GPIO_OUTPUT_IO_0);//set
		//GPIO.out_w1ts = (1<<GPIO_OUTPUT_IO_1);//set
		M_PWMIO_SET
		delay_4us();
		RGB_data <<= 1;	
	}





}


static void send_OneFrame(u32_t RGB){
int byte_count = 100;

	send_preamble();
	send_head_RGB();
	while(byte_count--){
			send_RGB(RGB);
	}

	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();	
	
}

static void send_OneFrame_buf(u32_t *pbuf){
int byte_count = 100;
	
	send_preamble();
	send_head_RGB();
	while(byte_count--){
		send_RGB(*pbuf++);
	}

	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();
	delay_4us();	
	
}


//三色4灰度循环闪烁
static void send_test(void)
{
int cnt = 63;
int kind = 0;
u32_t RGB=0;

	while(1){

		cnt += 64;//16;		
		if(cnt>256){
			cnt=63;
			if(++kind >=3)
				kind = 0;
			
		}
		switch(kind){
			case 0:
				RGB=cnt;

				break;
			case 1:
				RGB=cnt<<8;

				break;
			case 2:
				RGB=cnt<<16;

				break;	
			default:
				break;
		}
		
		send_OneFrame(RGB);
		ESP_LOGI(TAG_XGY, "RGB:0x%08X,kind:%d, R:0x%X,G:0x%X,B:0x%X,cnt:%d\r\n\r\n",RGB,kind,(RGB>>16&0xff),(RGB>>8&0xff),(RGB&0xff),cnt);
		vTaskDelay(1000 / portTICK_RATE_MS);//1000/(1000/50)=50
		//vTaskDelay(20 / portTICK_RATE_MS);//1000/(1000/50)=50
	}
}





//从0到99号 流水单点绿过去
static void send_test_No(u32_t rgb){
int i = 0;
u32_t *p=buf_RGB;

	memset(buf_RGB, 0, sizeof(buf_RGB));

	for(i=0;i<C_LEN_BUF_RGB;i++){
		*p=rgb;
		send_OneFrame_buf(buf_RGB);
		//*p=0;
		p++;
		ESP_LOGI(TAG_XGY, "No:%i",i);
		vTaskDelay(300 / portTICK_RATE_MS);//1000/(1000/50)=50
	}
	
		
	


}



//xTaskCreate(&pwmled_task, "pwmled_task", 8192, NULL, 5, NULL);
static void pwmled_task(void *pvParameter)
{

	int i = 0;
	u32_t *p=buf_RGB;
	
		memset(buf_RGB, 0, sizeof(buf_RGB));
	
		for(i=0;i<C_LEN_BUF_RGB;i++){
			*p=C_RGB_G3;
			send_OneFrame_buf(buf_RGB);
			//*p=0;
			p++;
			ESP_LOGI(TAG_XGY, "pwmled_task No:%i",i);
			vTaskDelay(500 / portTICK_RATE_MS);//1000/(1000/50)=50
		}
		




	//ESP_LOGI(TAG_XGY, "pwmled_task No:%i",i);
}




void xgy_gpio_main()
{
	ESP_LOGI(TAG_XGY, "xgy_gpio_main()\r\n\r\n");
	ESP_LOGI(TAG_XGY,"xgy %s 	 McuVer:V%d\n",C_NOW_TIME, OTA_VERSION_MCU);

	gpio_config_t io_conf;
    //disable interrupt
    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 0;
    //configure GPIO with the given settings
    gpio_config(&io_conf);

    //interrupt of rising edge
    io_conf.intr_type = GPIO_PIN_INTR_POSEDGE;
    //bit mask of the pins, use GPIO4/5 here
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //set as input mode    
    io_conf.mode = GPIO_MODE_INPUT;
    //enable pull-up mode
    io_conf.pull_up_en = 1;
    gpio_config(&io_conf);

    //change gpio intrrupt type for one pin
    gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE);

    //create a queue to handle gpio event from isr
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
    //start gpio task
    xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);

    //install gpio isr service
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void*) GPIO_INPUT_IO_1);

    //remove isr handler for gpio number.
    gpio_isr_handler_remove(GPIO_INPUT_IO_0);
    //hook isr handler for specific gpio pin again
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);

    int cnt = 0;
		ESP_LOGI(TAG_XGY,"Test xgy_gpio %s",C_NOW_TIME); 
		ESP_LOGI(TAG_XGY,"1000 / portTICK_RATE_MS=%d portTICK_RATE_MS=%d",(int)(1000/portTICK_RATE_MS),portTICK_RATE_MS);

		//;xTaskCreate(&pwmled_task, "pwmled_task", 8192, NULL, 5, NULL);
		ESP_LOGI(TAG_XGY,"xTaskCreate(&pwmled_task..)");
#if 0
	do {
		printf("xgy %s cnt: %d	 McuVer:V%d\n",C_NOW_TIME, cnt++,OTA_VERSION_MCU);
		vTaskDelay(5000 / portTICK_RATE_MS);

		//gpio_set_level(GPIO_OUTPUT_IO_0, cnt % 2);
		//gpio_set_level(GPIO_OUTPUT_IO_1, ((cnt % 2)+1)%2);
	}
	while(1);
#else
		while(1)
		{
			//5
			//send_OneFrame(C_RGB_G);
			//vTaskDelay(15 / portTICK_RATE_MS);
			
			//send_OneFrame(C_RGB_R);
		
			//4 红绿蓝彩灭 巡轮 2S
			#define	C_500MS	500
			send_OneFrame(C_RGB_R);
			vTaskDelay(C_500MS / portTICK_RATE_MS);
			send_OneFrame(C_RGB_G);
			vTaskDelay(C_500MS / portTICK_RATE_MS);
			send_OneFrame(C_RGB_B);
			vTaskDelay(C_500MS / portTICK_RATE_MS);
			send_OneFrame(C_RGB_RGB);
			vTaskDelay(C_500MS / portTICK_RATE_MS);
			send_OneFrame(C_RGB_OFF);
			vTaskDelay(C_500MS/ portTICK_RATE_MS);
#if 0	


			//3 ------------------------------------------------
			//send_test_No(C_RGB_R);////从0到99号 流水单点绿过去
			//2------------------------------------------------
			//send_test();//三色4灰度循环闪烁
		//1  1s 一个灯
//----------------------------------------------------------------------------------
			//send_RGB(0x00AAAAAA);
			send_OneFrame(0x00FF0000);
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			vTaskDelay(1000 / portTICK_RATE_MS);
			send_OneFrame(0x0000FF00);
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			vTaskDelay(1000 / portTICK_RATE_MS);
			send_OneFrame(0x000000FF);
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			delay_4us();
			vTaskDelay(1000 / portTICK_RATE_MS);
#endif
			
			
		}

#endif
	


	
}  


#endif







static esp_err_t event_handler(void *ctx, system_event_t *event)
{
    switch (event->event_id) {
    case SYSTEM_EVENT_STA_START:
        esp_wifi_connect();
        break;
    case SYSTEM_EVENT_STA_GOT_IP:
        xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
        break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
        /* This is a workaround as ESP32 WiFi libs don't currently
           auto-reassociate. */
        esp_wifi_connect();
        xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
        break;
    default:
        break;
    }
    return ESP_OK;
}

static void initialise_wifi(void)
{
    tcpip_adapter_init();
    wifi_event_group = xEventGroupCreate();
    ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_WIFI_SSID,
            .password = EXAMPLE_WIFI_PASS,
        },
    };
    ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
    ESP_ERROR_CHECK( esp_wifi_start() );
}

/*read buffer by byte still delim ,return read bytes counts*/
static int read_until(char *buffer, char delim, int len)
{
//  /*TODO: delim check,buffer check,further: do an buffer length limited*/
    int i = 0;
    while (buffer[i] != delim && i < len) {
        ++i;
    }
    return i + 1;
}

/* resolve a packet from http socket
 * return true if packet including \r\n\r\n that means http packet header finished,start to receive packet body
 * otherwise return false
 * */
static bool read_past_http_header(char text[], int total_len, esp_ota_handle_t update_handle)
{
    /* i means current position */
    int i = 0, i_read_len = 0;
    while (text[i] != 0 && i < total_len) {
        i_read_len = read_until(&text[i], '\n', total_len);
        // if we resolve \r\n line,we think packet header is finished
        if (i_read_len == 2) {
            int i_write_len = total_len - (i + 2);
            memset(ota_write_data, 0, BUFFSIZE);
            /*copy first http packet body to write buffer*/
            memcpy(ota_write_data, &(text[i + 2]), i_write_len);

			
#ifdef	XGY_DEBUG
			ESP_LOGI(TAG_XGY,"handle:0x%X esp_ota_write:%d Byte\r\n%s\r\n",update_handle,i_write_len,ota_write_data);
			//ota_xgy: handle:0x1 esp_ota_write:0 Byte
#endif

            esp_err_t err = esp_ota_write( update_handle, (const void *)ota_write_data, i_write_len);
            if (err != ESP_OK) {
                ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err);
                return false;
            } else {
                ESP_LOGI(TAG, "esp_ota_write header OK");
                binary_file_length += i_write_len;
            }
            return true;
        }
        i += i_read_len;
    }
    return false;
}

static bool connect_to_http_server()
{
    ESP_LOGI(TAG, "Server IP: %s Server Port:%s", EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);
    sprintf(http_request, "GET %s HTTP/1.1\r\nHost: %s:%s \r\n\r\n", EXAMPLE_FILENAME, EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);

    int  http_connect_flag = -1;
    struct sockaddr_in sock_info;

    socket_id = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_id == -1) {
        ESP_LOGE(TAG, "Create socket failed!");
        return false;
    }

    // set connect info
    memset(&sock_info, 0, sizeof(struct sockaddr_in));
    sock_info.sin_family = AF_INET;
    sock_info.sin_addr.s_addr = inet_addr(EXAMPLE_SERVER_IP);
    sock_info.sin_port = htons(atoi(EXAMPLE_SERVER_PORT));

    // connect to http server
    http_connect_flag = connect(socket_id, (struct sockaddr *)&sock_info, sizeof(sock_info));
    if (http_connect_flag == -1) {
        ESP_LOGE(TAG, "Connect to server failed! errno=%d", errno);
        close(socket_id);
        return false;
    } else {
        ESP_LOGI(TAG, "Connected to server");
        return true;
    }
    return false;
}

static void __attribute__((noreturn)) task_fatal_error()
{
    ESP_LOGE(TAG, "Exiting task due to fatal error...");
    close(socket_id);
    (void)vTaskDelete(NULL);

    while (1) {
        ;
    }
}

typedef struct {
	char file[64];                     /*!< 文件目录 */
	uint32_t uint_version;             /*!< 版本号 */
    uint32_t uint_interval;            /*!< 查询时间 */
} ota_version_t;



static bool xgy_read_past_http_header(char text[], int total_len)
{

	

    /* i means current position */
    int i = 0, i_read_len = 0;
    while (text[i] != 0 && i < total_len) {
        i_read_len = read_until(&text[i], '\n', total_len);
        // if we resolve \r\n line,we think packet header is finished
        if (i_read_len == 2) {
            int i_write_len = total_len - (i + 2);
            memset(ota_write_data, 0, BUFFSIZE);
            /*copy first http packet body to write buffer*/
            memcpy(ota_write_data, &(text[i + 2]), i_write_len);

			


            esp_err_t err = ESP_OK;//esp_ota_write( update_handle, (const void *)ota_write_data, i_write_len);
            if (err != ESP_OK) {
                ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err);
                return false;
            } else {
                ESP_LOGI(TAG, "esp_ota_write header OK");
                binary_file_length += i_write_len;
            }
            return true;
        }
        i += i_read_len;
    }

		    return false;
}


//static void xgy_get_versionStru(ota_version_t	*ptr_ota_version_t)
static int xgy_get_versionStru(ota_version_t	*ptr_ota_version_t)

{
	ota_version_t	_ota_version_t=
	{
		"/1.bin",
		1,
		10,			
	};

		
		int res = -1;
		sprintf(http_request, "GET %s HTTP/1.1\r\nHost: %s:%s \r\n\r\n", "/ota.txt", EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);
	
		/*send GET request to http server*/
		res = send(socket_id, http_request, strlen(http_request), 0);
		if (res == -1) {
			ESP_LOGE(TAG, "Send GET request to server failed");
			task_fatal_error();
		} else {
			ESP_LOGI(TAG, "Send GET request to server succeeded");
		}
	
		 bool resp_body_start = false, flag = true;
    	/*deal with all receive packet*/
    	while (flag) {
        memset(text, 0, TEXT_BUFFSIZE);
        memset(ota_write_data, 0, BUFFSIZE);
        int buff_len = recv(socket_id, text, TEXT_BUFFSIZE, 0);
        if (buff_len < 0) { /*receive error*/
            ESP_LOGE(TAG, "Error: receive data error! errno=%d", errno);
            task_fatal_error();
        } else if (buff_len > 0 && !resp_body_start) { /*deal with response header*/
            memcpy(ota_write_data, text, buff_len);
            resp_body_start = xgy_read_past_http_header(text, buff_len);//first ack
            if(resp_body_start)
			{
				ESP_LOGI(TAG_XGY, "txt http ack: %dNByte  \r\n%s\r\n", buff_len,text);
				//        ota_xgy: http ack: 276NByte  update_handle:0x1
			}
            
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++			
	        } else if (buff_len > 0 && resp_body_start) { /*deal with response body*/
            memcpy(ota_write_data, text, buff_len);

            binary_file_length += buff_len;
            ESP_LOGI(TAG, "Have written image length %d", binary_file_length);
			ESP_LOGI(TAG_XGY, "txt http ack: %dNByte  \r\n%s\r\n", buff_len,ota_write_data);
			
#if 0
FILE=/esp32/esp32-ota-https.bin
VERSION=3
INTERVAL=10
#endif			
	
	char *p1;
	char *p2;
	char a[6];
	do 
	{
		p1 = strstr(ota_write_data,"FILE=")+sizeof("FILE=")-1;
		if(NULL==p1)
			break;
		p2=	 strstr(p1,"\r\n");
		if(p2 ==NULL)
			break;
		memset(_ota_version_t.file, 0, sizeof(_ota_version_t.file));
		strncpy((char *)&_ota_version_t.file,(const char*)p1,(p2-p1));
		p1 = strstr(ota_write_data,"VERSION=")+sizeof("VERSION=")-1;
		if(p1 ==NULL)
			break;
		p2=	 strstr(p1,"\r\n");
		if(p2 ==NULL)
			break;
		memset(a,0,sizeof(a));
		strncpy(a,(const char*)p1,(p2-p1));
		_ota_version_t.uint_version=atoi(a);
		p1 = strstr(ota_write_data,"INTERVAL=")+sizeof("INTERVAL=")-1;
		if(p1 ==NULL)
			break;
		p2=	 strstr(p1,"\r\n");
		if(p2 ==NULL)
			break;
		memset(a,0,sizeof(a));
		strncpy(a,(const char*)p1,(p2-p1));
		_ota_version_t.uint_interval=atoi(a);
		res = 0;
		//ESP_LOGI(TAG_XGY,"fil1:%s ver:%d time:%d\r\n\r\n\r\n",_ota_version_t.file,_ota_version_t.uint_version,_ota_version_t.uint_interval);
		
	} while (0);

	
		//ESP_LOGI(TAG_XGY,"fil2:%s ver:%d time:%d\r\n\r\n\r\n",_ota_version_t.file,_ota_version_t.uint_version,_ota_version_t.uint_interval);
			//xgy add
			flag = false;
			//xgy add
			
        } else if (buff_len == 0) {  /*packet over*/
            flag = false;
            ESP_LOGI(TAG, "xgy Connection closed, all packets received");
            close(socket_id);
        } else {
            ESP_LOGE(TAG, "xgy Unexpected recv result");
        }
    }
		  
	
		//恢复
		
		ESP_LOGI(TAG_XGY,"fil3:%s ver:%d time:%d\r\n\r\n\r\n",_ota_version_t.file,_ota_version_t.uint_version,_ota_version_t.uint_interval);
		sprintf(http_request, "GET %s HTTP/1.1\r\nHost: %s:%s \r\n\r\n", EXAMPLE_FILENAME, EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);

		ptr_ota_version_t->uint_version=_ota_version_t.uint_version;
		ptr_ota_version_t->uint_interval=_ota_version_t.uint_interval;
		strcpy(ptr_ota_version_t->file,_ota_version_t.file);
		return res;
}






static void ota_example_task(void *pvParameter)
{
    esp_err_t err;
    /* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */
    esp_ota_handle_t update_handle = 0 ;
    const esp_partition_t *update_partition = NULL;

    ESP_LOGI(TAG, "Starting OTA example...");

    const esp_partition_t *configured = esp_ota_get_boot_partition();
    const esp_partition_t *running = esp_ota_get_running_partition();

    assert(configured == running); /* fresh from reset, should be running from configured boot partition */
    ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
             configured->type, configured->subtype, configured->address);

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    /* Wait for the callback to set the CONNECTED_BIT in the
       event group.
    */
    xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
                        false, true, portMAX_DELAY);
    ESP_LOGI(TAG, "Connect to Wifi ! Start to Connect to Server....");

    /*connect to http server*/
    if (connect_to_http_server()) {
        ESP_LOGI(TAG, "Connected to http server");
    } else {
        ESP_LOGE(TAG, "Connect to http server failed!");
        task_fatal_error();
    }


#ifdef	XGY_DEBUG//add 增加读版本信息
	ota_version_t	my_ota_version_t={
	"1.bin",
	1,
	2,
	};
	
	if(xgy_get_versionStru(&my_ota_version_t) !=0){
		ESP_LOGI(TAG_XGY,"Read versionStru fail\r\n");
	}

	//xgy_get_versionStru();
	ESP_LOGI(TAG_XGY,"xgy_get_versionStru()\r\nFile2:%s ver:%d time:%d\r\n\r\n\r\n",my_ota_version_t.file,my_ota_version_t.uint_version,my_ota_version_t.uint_interval);

	if(my_ota_version_t.uint_version>OTA_VERSION_MCU)
		ESP_LOGI(TAG_XGY,"httpVer:%d > McuVer:%d will update..\r\n",my_ota_version_t.uint_version,OTA_VERSION_MCU);
	if(my_ota_version_t.uint_version <= OTA_VERSION_MCU)
		ESP_LOGI(TAG_XGY,"httpVer:%d <= McuVer:%d Dont need update\r\n",my_ota_version_t.uint_version,OTA_VERSION_MCU);


	

	//恢复 目录是用写死的"/ota.bin"还是 ota.txt 的第二行
	//;sprintf(http_request, "GET %s HTTP/1.1\r\nHost: %s:%s \r\n\r\n", EXAMPLE_FILENAME, EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);

	//如果想用http文件目录的话  ota.txt 则#if 0
#if	0
	sprintf(http_request, "GET %s HTTP/1.1\r\nHost: %s:%s \r\n\r\n", EXAMPLE_FILENAME, EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);
	ESP_LOGI(TAG_XGY,"Read must /ota http_request ---->%s",http_request);
#else
	ESP_LOGI(TAG_XGY,"xgy http_request from ota.txt line 2 ->%s",my_ota_version_t.file);
	sprintf(http_request, "GET %s HTTP/1.1\r\nHost: %s:%s \r\n\r\n", my_ota_version_t.file , EXAMPLE_SERVER_IP, EXAMPLE_SERVER_PORT);
	ESP_LOGI(TAG_XGY,"Read from  ota.txt http_request ---->%s",http_request);
#endif

	
#endif
//---------------------------------------------------------------------------------------------


    int res = -1;
    /*send GET request to http server*/
    res = send(socket_id, http_request, strlen(http_request), 0);
    if (res == -1) {
        ESP_LOGE(TAG, "Send GET request to server failed");
        task_fatal_error();
    } else {
        ESP_LOGI(TAG, "Send GET request to server succeeded");
    }





    update_partition = esp_ota_get_next_update_partition(NULL);
    ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
             update_partition->subtype, update_partition->address);
    assert(update_partition != NULL);

    err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "esp_ota_begin failed, error=%d", err);
        task_fatal_error();
    }
    ESP_LOGI(TAG, "esp_ota_begin succeeded");

    bool resp_body_start = false, flag = true;
    /*deal with all receive packet*/
    while (flag) {
        memset(text, 0, TEXT_BUFFSIZE);
        memset(ota_write_data, 0, BUFFSIZE);
        int buff_len = recv(socket_id, text, TEXT_BUFFSIZE, 0);
        if (buff_len < 0) { /*receive error*/
            ESP_LOGE(TAG, "Error: receive data error! errno=%d", errno);
            task_fatal_error();
        } else if (buff_len > 0 && !resp_body_start) { /*deal with response header*/
            memcpy(ota_write_data, text, buff_len);
            resp_body_start = read_past_http_header(text, buff_len, update_handle);
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++			
#ifdef	XGY_DEBUG
			if(resp_body_start)
			{
				ESP_LOGI(TAG_XGY, "http ack: %dNByte  update_handle:0x%X\r\n%s\r\n", buff_len,update_handle,text);
				//        ota_xgy: http ack: 276NByte  update_handle:0x1
			}

			if(my_ota_version_t.uint_version <= OTA_VERSION_MCU)	
				while(1);//;;;;;;;;;;;;;;;;;版本地升级任务取消
			//;while(1);





			
/*
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 285456
Accept-Ranges: bytes
Server: HFS 2.3 beta
Set-Cookie: HFS_SID=0.76191456685774; path=/; 
Last-Modified: Mon, 18 Sep 2017 17:56:51 GMT
Content-Disposition: attachment; filename="ota.bin";



I (8789) wifi: pm start, type:0		
*/			
#endif
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

			
        } else if (buff_len > 0 && resp_body_start) { /*deal with response body*/
            memcpy(ota_write_data, text, buff_len);
            err = esp_ota_write( update_handle, (const void *)ota_write_data, buff_len);
            if (err != ESP_OK) {
                ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err);
                task_fatal_error();
            }
            binary_file_length += buff_len;
            ESP_LOGI(TAG, "Have written image length %d", binary_file_length);
        } else if (buff_len == 0) {  /*packet over*/
            flag = false;
            ESP_LOGI(TAG, "Connection closed, all packets received");
            close(socket_id);
        } else {
            ESP_LOGE(TAG, "Unexpected recv result");
        }
    }

    ESP_LOGI(TAG, "Total Write binary data length : %d", binary_file_length);

    if (esp_ota_end(update_handle) != ESP_OK) {
        ESP_LOGE(TAG, "esp_ota_end failed!");
        task_fatal_error();
    }
    err = esp_ota_set_boot_partition(update_partition);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%x", err);
        task_fatal_error();
    }
    ESP_LOGI(TAG, "Prepare to restart system!");
    esp_restart();
    return ;
}

void app_main()
{
    // Initialize NVS.
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
        // OTA app partition table has a smaller NVS partition size than the non-OTA
        // partition table. This size mismatch may cause NVS initialization to fail.
        // If this happens, we erase NVS partition and initialize NVS again.
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK( err );
#if 0
    initialise_wifi();

	ESP_LOGI(TAG, "xgy test 2017-09-18\n\n\n");
	
    xTaskCreate(&ota_example_task, "ota_example_task", 8192, NULL, 5, NULL);
#endif


#ifdef M_ENB_GPIO
	xgy_gpio_main();
#endif


	
}
